package com.plane;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

public class GamePanel extends Panel implements Runnable, KeyListener {
    private Hero hero = new Hero();
    private Map map = new Map();
    private Bullet bullet;
    private ArrayList<Bullet> bullets = new ArrayList<>();
    private int addBullet = 5;
    private int addBulletCount = 0;
    private Npc npc;
    private ArrayList<Npc> npcs = new ArrayList<>();
    private int addNpc = 15;
    private int addNpcCount = 0;
    private int dataIndex = 0;
    private int lifes = 3;
    private boolean alive = true;
    private Anim anim;
    private ArrayList<Anim> anims = new ArrayList<>();
    private Boss boss;

//    Random random = new Random(12345l);
//    int a = random.nextInt(6);


    @Override
    public void run() {

        while (alive) {
            addNpc();
//            System.out.println(a);
            addBullet();

            map.move();

            hero.move();

            for (int i = bullets.size() - 1; i >= 0; i--) {
                bullet = bullets.get(i);
                bullet.move(bullets);
            }

            for (int i = npcs.size() - 1; i >= 0; i--) {
                npc = npcs.get(i);
                npc.move(npcs);
            }

            if (boss != null) {
                boss.move();
            }

            bulletCollideWithNpc();

            heroCollideWithNpc();

            bulletCollideWithBoss();

            repaint();

            try {
                Thread.sleep(40L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void bulletCollideWithBoss() {
        if (boss != null) {
            for (int i = bullets.size() - 1; i >= 0; i--) {
                bullet = bullets.get(i);
                if (bullet.x + bullet.width > boss.x && npc.x + boss.width > bullet.x
                        && bullet.y + bullet.height > boss.y && boss.y + boss.height > bullet.y) {
                    bullets.remove(bullet);
                    anim = new Anim(0, bullet.x, bullet.y);
                    anims.add(anim);
                    boss.hp--;
                    if (boss.hp == 0) {
                        boss = null;
                        dataIndex = 0;
                        break;
                    }
                }
            }
        }
    }

    private void addNpc() {
        addNpcCount++;
        if (addNpcCount == addNpc) {
            if (dataIndex < Data.data.length) {
                npc = new Npc(Data.data[dataIndex], hero);
//                npc = new Npc(Data.data[a]);
                npcs.add(npc);
                dataIndex++;
            } else {
                if (boss == null && npcs.size() == 0) {
                    boss = new Boss();
                }
            }
            addNpcCount = 0;
        }
    }

    private void addBullet() {
        addBulletCount++;
        if (addBulletCount == addBullet) {
            bullet = new Bullet(hero, -2);
            bullets.add(bullet);
            bullet = new Bullet(hero, 2);
            bullets.add(bullet);
            bullet = new Bullet(hero, 0);
            bullets.add(bullet);
            bullet = new Bullet(hero, -4);
            bullets.add(bullet);
            bullet = new Bullet(hero, 4);
            bullets.add(bullet);
            addBulletCount = 0;
        }
    }


    private void bulletCollideWithNpc() {
        for (int i = bullets.size() - 1; i >= 0; i--) {
            bullet = bullets.get(i);
            for (int j = npcs.size() - 1; j >= 0; j--) {
                npc = npcs.get(j);
                if (bullet.x + bullet.width > npc.x && npc.x + npc.width > bullet.x
                        && bullet.y + bullet.height > npc.y && npc.y + npc.height > bullet.y) {
                    bullets.remove(bullet);
                    anim = new Anim(0, bullet.x, bullet.y);
                    anims.add(anim);
                    npc.hp--;
                    if (npc.hp <= 0) {
                        npcs.remove(npc);
                        anim = new Anim(1, npc.x, npc.y);
                        anims.add(anim);
                    }
                }
            }
        }
    }

    private void heroCollideWithNpc() {
        for (int i = npcs.size() - 1; i >= 0; i--) {
            npc = npcs.get(i);
            if (hero.x + hero.width > npc.x && npc.x + npc.width > hero.x
                    && hero.y + hero.height > npc.y && npc.y + npc.height > hero.y) {
                lifes--;
                if (lifes > 0) {
                    anim = new Anim(0, hero.x, hero.y);
                    anims.add(anim);
                    hero = new Hero();
                } else {
                    alive = false;
                }
            }
        }
    }

    @Override
    public void update(Graphics g) {
        Image temp = createImage(Map.MAP_WIDTH, Map.MAP_HEIGHT);
        Graphics gTemp = temp.getGraphics();
        map.paint(gTemp, this);
        hero.paint(gTemp, this);
        for (int i = 0; i < bullets.size(); i++) {
            bullet = bullets.get(i);
            bullet.paint(gTemp, this);
        }
        for (int i = npcs.size() - 1; i >= 0; i--) {
            npc = npcs.get(i);
            npc.paint(gTemp, this);
        }
        for (int i = anims.size() - 1; i >= 0; i--) {
            anim = anims.get(i);
            anim.paint(gTemp, this, anims);
        }
        if (boss != null) {
            boss.paint(gTemp, this);
        }
        if (!alive) {
            Font font = new Font("楷体", Font.BOLD, 45);
            gTemp.setFont(font);
            gTemp.setColor(Color.red);
            gTemp.drawString("GAME OVER!", 130, 100);
        }
        g.drawImage(temp, 0, 0, this);
    }


    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        hero.pressed(e.getKeyCode());
    }

    @Override
    public void keyReleased(KeyEvent e) {
        hero.released(e.getKeyCode());
    }
}
